/*!
 * Score manager.
 */
#pragma once
#include "Singleton.h"
#include "collisionObserver.h"
#include "ScoreObserver.h"
#include "Publisher.h"
#include "Subscriber.h"	

/*!
 * Score manager class.
 */
class ScoreManager: public Singleton<ScoreManager>, public CollisionObserver
{
public:

	/*!
	 * Create the manager's singleton.
	 *
	 * \note maxScore is the number of goal required to win a game.
	 */
	static void CreateInstance(const uint8 maxScore);
	virtual ~ScoreManager();

	/*! 
	 * Init the score manager and set it as a subscriber for the physics component.
	 *
	 * \note Make sure that the physics component has been created before calling this.
	 */
	void init();
	
	/*! 
	 * Set the number of goal required to win a game.
	 */
	void setMaxScore(const uint8 maxScore);
	/*! 
	 * Return the number of goal required to win a game.
	 */
	const uint8 getMaxScore() const;
	
	/*! 
	 * Return the score manager.
	 *
	 * \note Players' scores will be set to 0.
	 */
	void reset();

	/*!
	 * Return player 1 score.
	 */
	const uint8& getPlayer1Score() const;
	/*!
	 * Return player 2 score.
	 */
	const uint8& getPlayer2Score() const;

	/*!
	 * Return true if one player won the game.
	 */
	bool gameOver() const;

	/*!
	 * Return true if player 1 won the game.
	 */
	bool player1Wins() const;
	/*!
	 * Return true if player 2 won the game.
	 */
	bool player2Wins() const;

	/*! 
	 * Raise a ScoreEvent.
	 */
	void fireScore(const uint8 scorePlayer1, const uint8 scorePlayer2);
	/*! 
	 * Return the publisher for the type ScoreObserver associated with the ScoreManager.
	 */
	Publisher<ScoreObserver>& getScorePublisher();

	/*! 
	 * CollisionEvent method, called by the publisher for the type CollisionObserver (for now, physicsComponent).
	 */
	virtual void CollisionEvent(const CollisionData& data);
	/*!
	 * Check if a given collision generates a goal.
	 */
	void checkCollision(const ObjectId& objectAId, const ObjectId& objectBId);

private:
	
	ScoreManager(const uint8 maxScore);

	/*!
	 * Check if a given collision generates a goal for the player 2.
	 */
	bool checkLeftGoal(const ObjectId& objectAId, const ObjectId& objectBId) const;
	/*!
	 * Check if a given collision generates a goal for the player 1.
	 */
	bool checkRightGoal(const ObjectId& objectAId, const ObjectId& objectBId) const;

	/*!
	 * Increment player 1 score.
	 */
	void player1Scored();
	/*!
	 * Increment player 2 score.
	 */
	void player2Scored();

	/*!
	 * Log the current scores.
	 */
	void logScores() const;

	const ObjectId m_ballId;
	const ObjectId m_LeftWallId;
	const ObjectId m_RightWallId;

	uint8 m_scorePlayer1;
	uint8 m_scorePlayer2;

	uint8 m_maxScore;

	Publisher<ScoreObserver> m_scorePublisher;

	SubscriberHelper<CollisionObserver> m_collisionSubscriber;
};